<?php

namespace App\Services;
use App\Models\Device;
use App\Models\Device485;
use App\Models\Device485Attr;
use Workerman\Timer;
use Illuminate\Support\Facades\Redis;
use Workerman\Mqtt\Client;

class ModelReceiveService
{

    protected $mqttClient;

    protected $influxClient;

    protected $influxStartSql; // 包含bucket 和 measurement的sql

    public function __construct(Client $mqttClient)
    {
        $this->mqttClient = $mqttClient;
        $this->influxClient = app()->make(\InfluxDB2\Client::class);
        $this->setup(); // 安装influxdb的sql
        $this->receive(); // 接受485的数据
    }

    /**
     * @return void
     */
    public function receive()
    {
        $this->mqttClient->onConnect = function ($mqtt) {
            //$mqtt->subscribe('/iot/whd/network/r/network_test/1234');
            $mqtt->subscribe('/iot/whd/network/s/network_test/1234');
            //$mqtt->subscribe('/whd1/network/test/r/1234');
        };

        $this->mqttClient->onMessage = function($topic, $content) {
            list($null, $iot, $whd, $type, $s, $account, $password) = explode('/',$topic);

            if ($type == 'network') { // 新的接入方式
                $content = bin2hex($content);
                $this->resolve($content, $type, $account, $topic);
            } else { // 旧的接入方式
                $data = json_decode($content, true);
                $data['account'] = $account;
                $data['pass']    = $password;
                $data['time']    = time();
                $data['time_at'] = date("Y-m-d H:i:s",$data['time']);
                $data['pull']    = $topic;
                $data['push']    = str_replace('/s/', '/r/', $topic);

                if (empty($data) or !is_array($data)) return '';

                switch ($type) {
//                case 'sl':     //消毒灯
//                    $slService = new DisinfectLightService($mqtt);
//                    $slService->mqttHandle($data);
//                    break;
//                case 'ir' :   //智能遥控器
//                    $irService = new AirConditionerRemoteService($mqtt);
//                    $irService->mqttHandle($data);
//                    break;
//                case 'ventilation':  // 通风柜，风阀
//                    $veService     = new VeService($mqtt);
//                    $veService->mqttHandle($data);
//                    break;
//                case 'ventilation':  // 通风柜，风阀
//                    $veService     = new VeService($mqtt);
//                    $veService->mqttHandle($data);
//                    break;
//                case 'LIQUID':      //水位检测 ///iot/whd/LIQUID/r/15512348 {"OptType": "STOPBEE"}  净音 主题 及数据格式 type为8
//                    $WaterService = new WaterService();
//                    $WaterService->mqttHandle($data);
//                    break;
//                case  'FH':      //WiFi智控通风蝶阀  //type 为9
//                    //  /iot/whd/FH/s/15713154/1234   {"OptType":"CB","STATUS":"2"}  status 0 stop 1 open 2 close
//                    //  /iot/whd/FH/r/15713154/1234   {"OptType": "CTL", "Command": "CLOSE"} STOP OPEN
//                    $FfService = new FFService();
//                    $FfService->mqttHandle($data);
//                    break;
                    default:
                        //Log::warning("Device Mqtt Type[{$type}] is not Found",$data);
                        break;
                }
            }
        };
    }

    /**
     * @param $content  接收mqtt的数据
     * @param $type   类型，这里固定死network
     * @param $account  网关
     * @param $topic 主题格式
     * @return void
     */
    protected function resolve($content, $type, $account, $topic)
    {
        $device_id = Device::where(['account' => $account])->value('id'); // 找到其网关
        $address = substr($content, 0, 2);
        $sensor = Device485::where(['device_id' => $device_id, 'address' => $address])->first(); // 根据地址码及网关的设备号找到传感器
        $sensor_attrs = Device485Attr::where(['pid' => $sensor['model_id']])->first();
        if ($sensor_attrs && $sensor) {
            $this->getData(substr($content, 4), $sensor_attrs, $device_id, $address);
        }
    }

    /**
     * device_id    网关设备号
     * address      地址码，2位
     * @param $content   收到的mqtt数据,去掉地址头和功能码
     * @param $sensor_attrs 收到的sensor_attrs
     * @return void
     */
    protected function getData($content, $sensor_attrs, $device_id, $address)
    {
        $byteNum = substr($content, 0, 2); // 提前其有效字节数
        $others = substr($content, 2);
        if ($sensor_attrs['byte_num'] == $byteNum) { // 判断mqtt收到的字节数和数据库的字节数是否相等，只有相等才开始解析数值并上传到influxdb
            if ($sensor_attrs['byte_num'] == '02') { // 有效字节是2个  一个字节是由2位16进制数字组成
                $datastr = substr($others, 0, intval($sensor_attrs['byte_num']) * 2);
                $data = $this->processHexData($datastr, $sensor_attrs['formula']);
                $str = "sy_test,sensor={$device_id}_{$address} {$sensor_attrs['name']}={$data}";
                $this->influxClient->createWriteApi()->write($str);
            } elseif ($sensor_attrs['byte_num'] == '04') { // 有效字节是4个 一个字节是由2位16进制数字组成
                $datastr = substr($others, 0, intval($sensor_attrs['byte_num']) * 2);
                if ($sensor_attrs['name'] == '温湿度') {
                    $humidity = $this->processHexData(substr($datastr, 0, 4), $sensor_attrs['formula']);
                    $temperature = $this->processHexData(substr($datastr, 4), $sensor_attrs['formula']);
                    $str = "sy_test,sensor={$device_id}_{$address} 湿度={$humidity},温度={$temperature}";
                    $this->influxClient->createWriteApi()->write($str);
                }
            }
        }
        $this->influxClient->close(); // 关闭influx连接
    }


    /**
     * @param $symbol 来自数据库表中的/10，*100等
     * @param $datastr 16进制字符串
     * @return float|int 解析16进制的数值
     */
    protected function processHexData($dataStr, $formula = [])
    {
        $data = 0;
        if (empty($formula)) {
            $data = hexdec($dataStr);
        } else {
            $operator = substr($formula, 0, 1);
            $num = intval(substr($formula, 1));
            switch ($operator) {
                case '/':
                    $data = hexdec($dataStr) / $num;
                    break;
                case '*':
                    $data = hexdec($dataStr) * $num;
                    break;
            }
        }
        return $data;
    }


    public function setup()
    {
        $flux = "from(bucket: \"" . env('INFLUX_BUCKET') . "\")";

        $this->influxStartSql = $flux;
    }

    public function test($sensor, $field)
    {
        $sensor = " |> filter(fn: (r) => r[\"sensor\"] == \"" . $sensor ."\")";
        $field = " |> filter(fn: (r) => r[\"_field\"] == \"". $field ."\")";
        $measurement = " |> filter(fn: (r) => r[\"_measurement\"] == \"" . env("INFLUX_MEASUREMENT") . "\")";
        $end = time();
        $endRFC3339 = date(DATE_RFC3339, $end);
        $timeSlot = " |> range(start: -1h, stop: {$endRFC3339})";
        $last = " |> last()";//获取最后一条数据
        var_dump($this->influxStartSql . $timeSlot . $measurement.$sensor . $field);
    }

}

